import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

// 在介绍Row和Colum时，如果子widget超出屏幕范围，则会报溢出错误
// 这是因为Row默认只有一行，如果超出屏幕不会折行。
// 我们把超出屏幕显示范围会自动折行的布局称为流式布局
class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return Scaffold(
      appBar: new AppBar(
        title: new Text('流式布局Wrap'),
      ),
      body: new Container(
        color: Colors.orange,
        child: new Wrap(
          spacing: 10, // 水平方向间距
          runSpacing: 4, // 垂直方向间距
          alignment: WrapAlignment.start, // 方向
          // verticalDirection: VerticalDirection.up,
          children: <Widget>[
            new Text(
              'hello world',
              style: TextStyle(fontSize: 25),
            ),
            new Text('hello world'),
            new Text('hello world'),
            new Text('hello world'),
            new Text('hello world'),
            new Text(
              'hello world',
              style: TextStyle(fontSize: 25),
            ),
            new Text('hello world'),
            new Chip(
              avatar: new CircleAvatar(
                backgroundColor: Colors.blue,
                child: new Text('H'),
              ),
              label: new Text('Hamilton'),
            ),
            new Chip(
              avatar: new CircleAvatar(
                backgroundColor: Colors.blue,
                child: new Text('L'),
              ),
              label: new Text('Lafayette'),
            ),
            new Chip(
              avatar: new CircleAvatar(
                backgroundColor: Colors.blue,
                child: new Text('M'),
              ),
              label: new Text('Mulligan'),
            ),
            new Chip(
              avatar: new CircleAvatar(
                backgroundColor: Colors.blue,
                child: new Text('L'),
              ),
              label: new Text('Laurens'),
            ),
            new RaisedButton(
              child: new Text('push Flow'),
              onPressed: () {
                Navigator.push(context,
                    new MaterialPageRoute(builder: (context) {
                  return new FlowPage();
                }));
              },
            )
          ],
        ),
      ),
    );
  }
}

/* 
我们一般很少会使用Flow，因为其过于复杂，需要自己实现子widget的位置转换，
在很多场景下首先要考虑的是Wrap是否满足需求。
Flow主要用于一些需要自定义布局策略或性能要求较高(如动画中)的场景。Flow有如下优点：

性能好；Flow是一个对child尺寸以及位置调整非常高效的控件，
Flow用转换矩阵（transformation matrices）在对child进行位置调整的时候进行了优化：
在Flow定位过后，如果child的尺寸或者位置发生了变化，
在FlowDelegate中的paintChildren()方法中调用context.paintChild 进行重绘，
而context.paintChild在重绘时使用了转换矩阵（transformation matrices），并没有实际调整Widget位置。
灵活；由于我们需要自己实现FlowDelegate的paintChildren()方法，
所以我们需要自己计算每一个widget的位置，因此，可以自定义布局策略。

缺点：

使用复杂.
不能自适应子widget大小，必须通过指定父容器大小或实现TestFlowDelegate的getSize返回固定大小。
*/

class FlowPage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() {
    // TODO: implement createState
    return new FlowPageState();
  }
}

class FlowPageState extends State<FlowPage> {
  @override
  Widget build(BuildContext context) {
    // TODO: implement build
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('flow'),
      ),
      body: new Container(
        color: Colors.orange,
        child: new Flow(
          delegate: TestFlowDelegate(margin: EdgeInsets.all(10)),
          children: <Widget>[
            new Container(
              width: 80.0,
              height: 80.0,
              color: Colors.red,
            ),
            new Container(
              width: 80.0,
              height: 80.0,
              color: Colors.green,
            ),
            new Container(
              width: 80.0,
              height: 80.0,
              color: Colors.blue,
            ),
            new Container(
              width: 80.0,
              height: 80.0,
              color: Colors.yellow,
            ),
            new Container(
              width: 80.0,
              height: 80.0,
              color: Colors.brown,
            ),
            new Container(
              width: 80.0,
              height: 80.0,
              color: Colors.purple,
            ),
          ],
        ),
      ),
    );
  }
}

class TestFlowDelegate extends FlowDelegate {
  EdgeInsets margin = EdgeInsets.zero;
  TestFlowDelegate({this.margin});

  @override
  void paintChildren(FlowPaintingContext context) {
    // TODO: implement paintChildren
    var x = margin.left;
    var y = margin.top;
    // 计算每一个子widget的位置
    for (var i = 0; i < context.childCount; i++) {
      var left = context.getChildSize(i).width + x + margin.right;
      if (left < context.size.width) {
        context.paintChild(i,
            transform: new Matrix4.translationValues(x, y, 0.0));
        x = left + margin.left;
      } else {
        x = margin.left;
        y += context.getChildSize(i).height + margin.top + margin.bottom;
        context.paintChild(i,
            transform: new Matrix4.translationValues(x, y, 0.0));
        x += context.getChildSize(i).width + margin.left + margin.right;
      }
    }
  }

  @override
  Size getSize(BoxConstraints constraints) {
    // TODO: implement getSize
    return Size(double.infinity, 200);
  }

  @override
  bool shouldRepaint(FlowDelegate oldDelegate) {
    // TODO: implement shouldRepaint
    return oldDelegate != this;
  }
}
